<?php

/**
 * Проверяет загруженный файл изображения.
 *
 */
class Kernel_Validator_Image extends Kernel_Validator_Abstract {

    /**
     * Количество пикселей в мегапикселе :)
     *
     */
    const MEGAPIXEL = 1048576;

    /**
     * Коэффициент, указывающий, какую долю оперативной памяти можно отвести на
     * обработку изображения.
     *
     */
    const MEMORY_FACTOR = 0.75;

    /**
     * Максимальный разрешенный размер/размеры изображения.
     *
     * @var integer
     */
    public $max;

    /**
     * Минимальный разрешенный размер/размеры изображения.
     *
     * @var integer
     */
    public $min;

    /**
     * Сообщение об ошибке неподдерживаемого типа изображения. Понадобилось для
     * проекта, если понадобится подправлять остальные, добавлю потом.
     *
     * @var string
     */
    public $message_unsupported_type = 'IMAGE_UNSUPPORTED_TYPE';

    /**
     * Разрешенные типы изображений.
     *
     * @var array
     */
    public $types = array();

    /**
     * Проверяемый файл. Ну надо, чтоб он тут был.
     *
     * @var Kernel_Form_Value_File
     */
    private $_value;

    /**
     * Конструктор.
     *
     * @param   array   $params
     */
    public function __construct($params = array()) {
        parent::__construct($params);
        if (empty($this->max)) {
            $this->max = $this->_getMaxSize();
        }
    }

    /**
     * Проверяет правильность указанного значения
     *
     * @param   Kernel_Form_Value_File   $file
     * @throws  Kernel_Validator_Exception
     */
    protected function _validate($file) {

        // сохраняем ссылку на файл, чтобы потом убить при необходимости
        $this->_value = $file;

        // проверяем, является ли загруженный файл изображением
        if (!is_array($info = getimagesize($file->getPath()))) {
            $this->_error(__($this->message_unsupported_type));
        }

        // определяем параметры изображения
        list($width, $height, $type) = $info;

        // проверяем, является ли загруженный файл изображением
        if (!empty($this->types) && !in_array($type, $this->types)) {
            $this->_error(__($this->message_unsupported_type));
        }
        
        /// ????
        // проверяем на соответствие минимально допустимым размерам
        /*if (is_float($this->min)) {
            if ($width * $height < self::MEGAPIXEL * $this->min) {
                $this->_error(__('IMAGE_MPX_LESS_THAN', $this->min));
            }
        } else {
            list($min_width, $min_height) = $this->_getParams($this->min);
            if (($min_width > 0 && $width < $min_width) || ($min_height > 0 && $height < $min_height)) {
                $this->_sizeError('LESS', $min_width, $min_height);
            }
        }*/
        
        /// ????
        // проверяем на соответствие максимально допустимым размерам
        /*if (is_float($this->max)) {
            if ($width * $height > self::MEGAPIXEL * $this->max) {
                $this->_error(__('IMAGE_MPX_GREATER_THAN', $this->max));
            }
        } else {
            list($max_width, $max_height) = $this->_getParams($this->max);
            if (($max_width > 0 && $width > $max_width) || ($max_height > 0 && $height > $max_height)) {
                $this->_sizeError('GREATER', $max_width, $max_height);
            }
        }*/
    }

    /**
     * Возвращает значения предельных ширины и высоты, полученный из параметров
     * компонента.
     *
     * @param   mixed   $extreme
     * @return  array
     */
    private function _getParams($extreme) {
        switch (true) {
            case empty($extreme):
                return array(null, null);
            case is_scalar($extreme):
                return array($extreme, $extreme);
            case is_array($extreme):
                return $extreme;
            default:
                trigger_error('Incorrect extreme params specified', E_USER_WARNING);
                return array(null, null);
        }
    }

    /**
     * Регистрирует указанное сообщение об ошибке.
     *
     * @param   string  $message
     */
    protected function _error($message = null) {
        // грохаем файл, так как он не подходит, и, значит, нам не нужен
        $this->_value->destruct();
        parent::_error($message);
    }

    /**
     * Формирует сообщение об ошибке несоответствия размеров изображения
     * предельно допустимым.
     *
     * @param   string  $error
     * @param   integer $width
     * @param   integer $height
     */
    private function _sizeError($error, $width, $height) {
        switch (true) {
            case $width > 0 && $height > 0:
                $size = 'SIZE';
                break;
            case $width > 0:
                $size = 'WIDTH';
                break;
            case $height > 0:
                $size = 'HEIGHT';
                break;
        }
        $this->_error(__('IMAGE_' . $size . '_' . $error . '_THAN', $width, $height));
    }

    /**
     * Возвращает максимально допустимый размер изображения
     *
     * @return  float
     */
    private function _getMaxSize() {
        return (int)ini_get('memory_limit') * self::MEMORY_FACTOR / 3;
    }
}
